#!/usr/bin/env ruby

LKP_SRC = ENV['LKP_SRC'] || File.dirname(File.dirname(File.realpath($PROGRAM_NAME)))

require "#{LKP_SRC}/lib/statistics"
require "#{LKP_SRC}/lib/log"

bytes = 0
kbps = []
throughput = []
median = []
bytes_fault = 0
kbps_fault = []
throughput_fault = []
median_fault = []
free_secs = []
ret = {}
ret['warned'] = false

def add_one_sample(kbps, throughput, median, ret)
  return if kbps.empty?

  throughput << kbps.sum
  kbps.sort!
  median << kbps[kbps.size / 2]
  puts "# #{kbps.size} #{kbps.sum}"
  return unless kbps.size != 1 && (kbps.size & 1) != 0 && !ret['warned']

  log_warn "stats/vm-scalability: possibly disordered output #{ARGV[0]}"
  ret['warned'] = true
end

while (line = $stdin.gets)
  case line
  when /^\.*(\d+) bytes \/ (\d+) usecs = (\d+) KB.s/
    bytes += $1.to_i
    kbps << $3.to_i
  when /(\d+) bytes \([0-9.]+ .B(?:, [0-9.]+ .iB)?\) copied, ([0-9.]+) s, ([0-9.]+) .B.s/
    bytes += $1.to_i
    kbps << ($1.to_i >> 10) / $2.to_f
  when /(\d+) bytes truncated in ([0-9.]+)-([0-9.]+) seconds/
    bytes += $1.to_i
    kbps << ($1.to_i >> 10) / ($2.to_f - $3.to_f)
  when /(\d+) bytes faulted in ([0-9.]+)-([0-9.]+) seconds/
    bytes_fault += $1.to_i
    kbps_fault << ($1.to_i >> 10) / ($2.to_f - $3.to_f)
  when /\d+ \* \d+ bytes migrated, \d+ usecs, (\d+) MB.s/
    bytes += $1.to_i
    puts "RATE.migrate_mbps: #{$1}"
  when /(\d+) bytes remapped, (\d+) usecs, (\d+) MB.s/
    bytes += $1.to_i
    kbps << $1.to_i / ($2.to_i >> 10)
  when /(\d+) usecs to free memory/
    free_secs << $1.to_i / 1_000_000.0
  when /\.\/case-[a-z-]+/
    add_one_sample(kbps, throughput, median, ret)
    add_one_sample(kbps_fault, throughput_fault, median_fault, ret)
    kbps.clear
    kbps_fault.clear
  end
end

add_one_sample(kbps, throughput, median, ret)
add_one_sample(kbps_fault, throughput_fault, median_fault, ret)
exit if throughput.empty?

def cal_stddev(throughput, kbps)
  return throughput.standard_deviation / throughput.average if throughput.size > 1

  kbps.standard_deviation * kbps.size / kbps.average
end

def cal_median_stddev(median)
  return median.standard_deviation / median.average if median.size > 1

  0
end

# Relative standard deviation
stddev = cal_stddev(throughput, kbps)

median_stddev = cal_median_stddev(median)

printf "RATE.throughput: %d\n", throughput.average
if kbps.empty?
  log_error 'stats/vm-scalability: incomplete output'
  exit
end
printf "JIT.stddev%%:   %g\n", stddev * 100
printf "LAT.free_time:  %g\n", free_secs.average unless free_secs.empty?
printf "median: %d\n", median.average
printf "JIT.median_stddev%%: %g\n", median_stddev * 100
printf "gauge.workload: %.2f\n", bytes.to_f / 1024

unless throughput_fault.empty?
  printf "RATE.throughput_fault: %d\n", throughput_fault.average
  stddev = cal_stddev(throughput_fault, kbps_fault)
  printf "JIT.stddev_fault%%:   %g\n", stddev * 100
  median_fault_stddev = cal_median_stddev(median_fault)
  printf "median_fault: %d\n", median_fault.average
  printf "JIT.median_fault_stddev%%: %g\n", median_fault_stddev * 100
end
